package com.lsh.ofc.core.handler.logistics;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.lsh.base.common.exception.BusinessException;
import com.lsh.ofc.core.base.AbstractTask;
import com.lsh.ofc.core.entity.OfcOrderHead;
import com.lsh.ofc.core.entity.OfcSoHead;
import com.lsh.ofc.core.enums.FulfillChannel;
import com.lsh.ofc.core.enums.LogisticsTypeEnum;
import com.lsh.ofc.core.enums.Org2System;
import com.lsh.ofc.core.enums.SoStatus;
import com.lsh.ofc.core.exception.EC;
import com.lsh.ofc.core.model.SoMergeOrderInfoBO;
import com.lsh.ofc.core.service.OfcOrderService;
import com.lsh.ofc.core.service.OfcSoMergeNotifyOtherSystemService;
import com.lsh.ofc.proxy.context.WumartBasicContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.*;

/**
 * Project Name: AbstractLogisticsHandler
 * 北京链商电子商务有限公司
 *
 * @author: wangliutao
 * Date: 19/2/26AbstractLogisticsHandler
 * Package Name: com.lsh.ofc.core.handler.logistics
 * Description:
 */
@Slf4j
public abstract class AbstractLogisticsHandler extends AbstractTask<Boolean> {
    protected final List<OfcSoHead> sos;
    protected final OfcOrderHead ofcOrderHead;
    protected final OfcOrderService ofcOrderService;
    protected final OfcSoMergeNotifyOtherSystemService ofcSoMergeNotifyOtherSystemService;

    protected AbstractLogisticsHandler(final ApplicationContext context, final OfcOrderHead ofcOrderHead, final List<OfcSoHead> sos) {
        Assert.notNull(context, "context can not be null!");
        Assert.notNull(ofcOrderHead, "ofcOrderHead can not be null!");
        Assert.notEmpty(sos, "sos can not be empty!");
        this.sos = sos;
        this.ofcOrderHead = ofcOrderHead;
        this.ofcOrderService = context.getBean(OfcOrderService.class);
        this.ofcSoMergeNotifyOtherSystemService = context.getBean(OfcSoMergeNotifyOtherSystemService.class);
    }

    /**
     *
     * @param context
     * @param LogisticsType
     * @param ofcOrderHead
     * @param sos
     * @return
     */
    public static final AbstractLogisticsHandler newInstance(final ApplicationContext context, final Integer LogisticsType, final OfcOrderHead ofcOrderHead, final List<OfcSoHead> sos) {
        Assert.notNull(context, "context can not be null!");
        Assert.notNull(LogisticsType, "LogisticsType can not be null!");
        Assert.notNull(ofcOrderHead, "ofcOrderHead can not be null!");
        Assert.notEmpty(sos, "sos can not be empty!");

        LogisticsTypeEnum logisticsType = LogisticsTypeEnum.valueOf(LogisticsType);
        if (logisticsType == null) {
            throw EC.ERROR.exception("logisticsType is not support!!! logisticsType=" + logisticsType);
        }

        try {
            return logisticsType.getLogisticsHandler().getDeclaredConstructor(ApplicationContext.class, OfcOrderHead.class, List.class).newInstance(context, ofcOrderHead, sos);
        } catch (Exception e) {
            throw EC.ERROR.exception(e);
        }
    }

    @Override
    public Boolean execute() throws BusinessException {
        Long orderCode = ofcOrderHead.getOrderCode();
        SoMergeOrderInfoBO orderInfo = new SoMergeOrderInfoBO();
        try {

            JSONObject headExt = JSON.parseObject(ofcOrderHead.getExt());
            Long pOrderCode = headExt.getLong("parent_order_code");
            if (null == pOrderCode || pOrderCode == 0) {
                pOrderCode = orderCode;
            }

            String orderDc = "";
            List<String> soCodes = new ArrayList<>();
            List<String> soBillCodes = new ArrayList<>();
            Set<String> warehouseCodes = new HashSet<>(sos.size());
            BigDecimal totalSkuOrderQty = BigDecimal.ZERO;
            BigDecimal totalSkuSupplyQty = BigDecimal.ZERO;
            Map<String, Integer> sourceSystem = new HashMap<>();
            List<Integer> soSupplyOrg = new ArrayList<>();
            List<String> mpCustCodes = new ArrayList<>();
            // 该集合中，可能包含soBillCode、soCode
            List<String> mixtureSoCodes = new ArrayList<>();
            Integer orderType = null;
            Integer cusType = null;
            String supplierCode = null;
            for (OfcSoHead so : sos) {
                if (so == null) {
                    continue;
                }

                JSONObject soExt = JSON.parseObject(so.getExt());
                if (soExt != null) {
                    String mpCustomerCode = soExt.getString("mp_cust_code");
                    if (!mpCustCodes.contains(mpCustomerCode)) {
                        mpCustCodes.add(mpCustomerCode);
                    }
                    cusType = soExt.getInteger(WumartBasicContext.CUSTYPE);
                    // ofc_supplier表中code字段
                    supplierCode = soExt.getString("supplier_code");
                    orderDc = supplierCode;
                }

                int org = so.getSupplierOrg();
                soSupplyOrg.add(org);

                // TODO ?
                if (FulfillChannel.SAAS_SC.getValue().equals(so.getFulfillChannel())) {
                    sourceSystem.put(so.getSoBillCode(), 2);
                } else {
                    sourceSystem.put(so.getSoBillCode(), this.getSourceCode(org));
                }

               Integer deliveryType = soExt.getInteger("deliveryType");

                if (null != deliveryType && deliveryType == 3) {
                    // todo：云仓订单 下发tms 与 psi 不同
                    orderType = 4;
                } else {
                    orderType = 1;
                }

                String soCode = so.getSoCode();
                if (SoStatus.CREATED.getValue() > so.getSoStatus() || !StringUtils.hasText(soCode)) {
                    log.warn("订单对应SO未全部创建完成...订单号=" + orderCode + "，SO单号=" + so.getSoCode() + "，SO状态=" + so.getSoStatus());
                    return Boolean.FALSE;
                }

                // so单号，物美系统提交排线是按照下游so_code排线
                if (so.getFulfillChannel().equals(FulfillChannel.WUMART_OFC.getValue()) || so.getFulfillChannel().equals(FulfillChannel.WUMART_SAP.getValue())) {
                    mixtureSoCodes.add(so.getSoCode());
                } else {
                    mixtureSoCodes.add(so.getSoBillCode());
                }

                soCodes.add(soCode);
                String warehouseCode = this.getWarehouseCode(so, supplierCode);
                warehouseCodes.add(warehouseCode);
                soBillCodes.add(so.getSoBillCode());
                totalSkuOrderQty = totalSkuOrderQty.add(so.getTotalSkuOrderQty());
                totalSkuSupplyQty = totalSkuSupplyQty.add(so.getTotalSkuSupplyQty());

                orderInfo.setVenderId(so.getVenderId());
            }

            if (StringUtils.isEmpty(orderDc)) {
                log.info("{} orderDc 不能为空", orderCode);
                return Boolean.FALSE;
            }

            orderInfo.setMixtureSoCodes(mixtureSoCodes);
            orderInfo.setPOrderCode(pOrderCode);
            orderInfo.setOrderCode(orderCode);
            orderInfo.setOrderDc(orderDc);
            orderInfo.setCusType(cusType);
            orderInfo.setMpCustCodes(mpCustCodes);
            orderInfo.setTotalSkuOrderQty(totalSkuOrderQty);
            orderInfo.setTotalSkuSupplyQty(totalSkuSupplyQty);
            orderInfo.setOfcOrderHead(ofcOrderHead);
            orderInfo.setSoHeads(sos);
            orderInfo.setSoCodes(soCodes);
            orderInfo.setSoBillCodes(soBillCodes);
            orderInfo.setWarehouseCodes(warehouseCodes);
            orderInfo.setSourceSystem(sourceSystem);
            orderInfo.setSoSupplyOrg(soSupplyOrg);
            orderInfo.setOrderType(orderType);
            //执行目标流程
            Boolean isSuccess = this.process(orderInfo);
            //更新OFC订单接单数量
            this.updateOfcOrderHead(orderCode, totalSkuSupplyQty, ofcOrderHead.getVenderId());

            return isSuccess;
        } catch (Throwable e) {
            log.error("【" + orderCode + "】SO Merge异常" + e.getMessage(), e);
            return false;
        }
    }

    protected abstract Boolean process(final SoMergeOrderInfoBO orderInfo) throws BusinessException;

    protected String getWarehouseCode(OfcSoHead soHead, String supplierCode) throws BusinessException {
        String warehouseCode = soHead.getWarehouseCode();

        return warehouseCode;
    }

    /**
     * 更新订单供货数量
     *
     * @param orderCode
     * @param totalSkuSupplyQty
     */
    protected void updateOfcOrderHead(Long orderCode, BigDecimal totalSkuSupplyQty, Long venderId) {
        this.ofcOrderService.update4Create(orderCode, totalSkuSupplyQty, venderId);
    }

    /**
     * 根据机构获取来源
     *
     * @param org
     * @return
     */
    private int getSourceCode(int org) {
        Org2System org2System = Org2System.getOrg2System(org);
        if (null == org2System) {
            return 7;
        }

        return org2System.getSystem();
    }
}
